<?php
# ***** BEGIN LICENSE BLOCK *****
# This file is part of "myWiWall".
# Copyright (c) 2007-2008 CRP Henri Tudor and contributors.
# All rights reserved.
#
# "myWiWall" is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
# 
# "myWiWall" is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with "myWiWall"; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# ***** END LICENSE BLOCK *****
class Install
{
	private $configFileStreamIn;
	private $configFileIn;
	private $configFileOut;
	private $userParams;
	
	public function __construct($configFileIn, $configFileOut, $userParams)
	{
		$this->configFileIn = $configFileIn;
		$this->configFileStreamIn = $this->getConfigFileAsStream($configFileIn);
		$this->configFileOut = $configFileOut;
		$this->userParams = $userParams;
	}
	
	public function install()
	{
		$this->checkList();
		$this->createDatabase();
		$this->rewriteConfigFile();
	}
	
	private function checkList()
	{
		// MYSQL Support ?
		if (!function_exists('mysql_query'))
			throw new InstallException(InstallException::MISSING_MYSQL_FUNCTIONS,
									   'PHP is not compiled with MySQL functions');
									   
		// Sample config file present ?
		if (!is_file($this->configFileIn))
			throw new InstallException(InstallException::MISSING_CONFIG_SAMPLE,
									   'The sample configuration file is missing');
		
		// Sample config file readable ?
		if (!@is_readable($this->configFileIn))
			throw new InstallException(InstallException::CONFIG_SAMPLE_NOT_READABLE,
									   'The sample configuration file is not readable');
			
		// Include folder readable in order to create the config.php file ?
		if (!@is_writable(dirname($this->configFileIn)))
			throw new InstallException(InstallException::CONFIG_FOLDER_NOT_WRITABLE,
									   'The folder containing the configuration file is not writable');
			
		// Config file already generated ?
		if (is_file($this->configFileOut))
			throw new InstallException(InstallException::CONFIG_FILE_ALREADY_GENERATED,
									   'The configuration file was already generated');
			
		if (@!is_writable(dirname(__FILE__) . '/../../widgets'))
			throw new InstallException(InstallException::WIDGETS_FOLDER_NOT_WRITABLE,
									   'The widgets folder must be writable');
	}
	
	private function getConfigFileAsStream($configFile)
	{
		$fp = fopen($configFile, 'r');
		$fileStream = fread($fp, filesize($configFile));
		fclose($fp);
		
		return $fileStream;
	}
	
	private function rewriteConfigFile()
	{
		foreach ($this->userParams as $key => $value)
		{
			$value = addslashes($value);
			
			switch ($key)
			{
				case 'database_login':
					$this->configFileStreamIn = eregi_replace("define\(\"DATABASE_LOGIN\"[[:space:]]*,[[:space:]]*\"root\"\);",
															  "define(\"DATABASE_LOGIN\", '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'database_password':
					$this->configFileStreamIn = eregi_replace("define\(\"DATABASE_PASS\"[[:space:]]*,[[:space:]]*\"\"\);",
															  "define(\"DATABASE_PASS\", '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'database_url':
					$this->configFileStreamIn = eregi_replace("define\(\"DATABASE_URL\"[[:space:]]*,[[:space:]]*\"localhost\"\);",
															  "define(\"DATABASE_URL\", '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'database_name':
					$this->configFileStreamIn = eregi_replace("define\(\"DATABASE_NAME\"[[:space:]]*,[[:space:]]*\"palette_portal\"\);",
															  "define(\"DATABASE_NAME\", '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'theme_name':
					$this->configFileStreamIn = eregi_replace('\$GLOBALS\[\'dir_theme\'\][[:space:]]*=[[:space:]]*\'default/\';',
															  '$GLOBALS[\'dir_theme\'] = \'' . $value . '/\';',
															  $this->configFileStreamIn);
				break;
				
				case 'language':
					$this->configFileStreamIn = eregi_replace('\$GLOBALS\[\'lang\'\][[:space:]]*=[[:space:]]*\'en\';',
															  '$GLOBALS[\'lang\'] = \'' . $value . '\';',
															  $this->configFileStreamIn);
				break;
				
				case 'openid_mode':
					$this->configFileStreamIn = eregi_replace("define\('OPENID_SSO_MODE'[[:space:]]*,[[:space:]]*false\);",
															  "define('OPENID_SSO_MODE', ${value});",
															  $this->configFileStreamIn);
				break;
				
				case 'application_name':
					$this->configFileStreamIn = eregi_replace("define\('APPNAME'[[:space:]]*,[[:space:]]*''\);",
															  "define('APPNAME', \"${value}\");",
															  $this->configFileStreamIn);
				break;
				
				case 'logs_users_activate':
					$this->configFileStreamIn = eregi_replace("define\('LOGS_USERS'[[:space:]]*,[[:space:]]*false\);",
															  "define('LOGS_USERS', ${value});",
															  $this->configFileStreamIn);
				break;
				
				case 'logs_users_path':
					$this->configFileStreamIn = eregi_replace("define\('LOGS_USERS_SRC'[[:space:]]*,[[:space:]]*''\);",
															  "define('LOGS_USERS_SRC', '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'service_browser_activate':
					$this->configFileStreamIn = eregi_replace("define\('USE_SERVICE_BROWSER'[[:space:]]*,[[:space:]]*false\);",
															  "define('USE_SERVICE_BROWSER', ${value});",
															  $this->configFileStreamIn);
				break;
				
				case 'service_browser_uri':
					$this->configFileStreamIn = eregi_replace("define\('SERVICE_BROWSER_URI'[[:space:]]*,[[:space:]]*''\);",
															  "define('SERVICE_BROWSER_URI', '${value}');",
															  $this->configFileStreamIn);
				break;
				
				case 'portal_uri':
					// Here we can determine the BASE_WS_URL and the BASE_PREVIEW_URI parameters.
					$value = $this->clearEndOfURI($value);
					
					$this->configFileStreamIn = eregi_replace("define\('BASE_WS_URL'[[:space:]]*,[[:space:]]*''\);",
															  "define('BASE_WS_URL', '${value}/ws/index.php/');",
															  $this->configFileStreamIn);
															  
					$this->configFileStreamIn = eregi_replace("define\('BASE_PREVIEW_URI'[[:space:]]*,[[:space:]]*''\);",
															  "define('BASE_PREVIEW_URI', '${value}/ws/previews/');",
															  $this->configFileStreamIn);
															  
					$this->configFileStreamIn = eregi_replace("define\('BASE_PORTAL_URI'[[:space:]]*,[[:space:]]*''\);",
															  "define('BASE_PORTAL_URI', '${value}/');",
															  $this->configFileStreamIn);
				break;
			}
		}
		
		// We finish by writing the configuration file on the file system.
		$fp = fopen($this->configFileOut ,'w');
		fwrite($fp, $this->configFileStreamIn, strlen($this->configFileStreamIn));
		fclose($fp);
	}
	
	private function createDatabase()
	{
		$exceptionToThrow = null;
		$transactionStarted = false;
		$params = $this->userParams;
		
		$server 	= $params['database_url'];
		$username 	= $params['database_login'];
		$password 	= $params['database_password'];
		
		if ($conn = @mysql_connect($server, $username, $password))
		{
			$database 	= mysql_real_escape_string($params['database_name']);
			
			// Beginning transaction.
			@mysql_query('START TRANSACTION;');
			@mysql_query('SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"');
			
			$transactionStarted = true;
			
			// Database creation.
			if (@mysql_query("CREATE DATABASE `${database}` CHARACTER SET utf8 COLLATE utf8_unicode_ci") &&
				@mysql_select_db($database, $conn))
			{
				
				// Tables creation.
				if (!@mysql_query('CREATE TABLE `categories` (
							`id` smallint(6) unsigned NOT NULL auto_increment,
							`category` varchar(50) collate utf8_unicode_ci NOT NULL,
							PRIMARY KEY  (`id`),
							UNIQUE KEY `category` (`category`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create categories table',
													   mysql_error());
				}
				
				if (!@mysql_query('CREATE TABLE `cops` (
							`copname` varchar(50) collate utf8_unicode_ci NOT NULL,
							`coplabel` varchar(100) collate utf8_unicode_ci default NULL,
							PRIMARY KEY  (`copname`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create cops table',
													   mysql_error());

				}
				
				if (!@mysql_query('CREATE TABLE `interface` (
							`userid` mediumint(8) unsigned NOT NULL,
							`widgetid` varchar(50) collate utf8_unicode_ci NOT NULL,
							`column` tinyint(4) unsigned NOT NULL default \'0\',
							`minimized` tinyint(1) NOT NULL default \'0\',
							`position` smallint(5) unsigned NOT NULL default \'0\',
							PRIMARY KEY  (`userid`,`widgetid`),
							KEY `widgetid` (`widgetid`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create interface table',
													   mysql_error());
				}
				
				if (!@mysql_query('CREATE TABLE `interface_preferences` (
							`userid` mediumint(8) unsigned NOT NULL,
							`widgetid` varchar(50) collate utf8_unicode_ci NOT NULL,
							`preference` varchar(50) collate utf8_unicode_ci NOT NULL,
							`value` varchar(255) collate utf8_unicode_ci default NULL,
							PRIMARY KEY  (`userid`,`widgetid`,`preference`),
							KEY `widgetid` (`widgetid`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create interface_preferences table',
													   mysql_error());
				}
				
				if (!@mysql_query('CREATE TABLE `oid_associations` (
							`server_url` blob NOT NULL,
							`handle` varchar(255) collate utf8_unicode_ci NOT NULL,
							`secret` blob NOT NULL,
							`issued` int(11) NOT NULL,
							`lifetime` int(11) NOT NULL,
							`assoc_type` varchar(64) collate utf8_unicode_ci NOT NULL,
							PRIMARY KEY  (`server_url`(255),`handle`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create oid_associations table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `oid_nonces` (
							`server_url` varchar(2047) collate utf8_unicode_ci NOT NULL,
							`timestamp` int(11) NOT NULL,
							`salt` char(40) collate utf8_unicode_ci NOT NULL,
							UNIQUE KEY `server_url` (`server_url`(255),`timestamp`,`salt`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create oid_nonces table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `tags` (
							`label` varchar(50) collate utf8_unicode_ci NOT NULL,
							PRIMARY KEY  (`label`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create tags table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `users` (
 								  `id` mediumint(8) unsigned NOT NULL auto_increment,
  								  `username` varchar(50) collate utf8_unicode_ci NOT NULL,
  								  `password` varchar(32) collate utf8_unicode_ci NOT NULL,
  								  `copname` varchar(50) collate utf8_unicode_ci default NULL,
  								  `level` tinyint(3) unsigned NOT NULL default \'0\',
  								  `lang` varchar(32) collate utf8_unicode_ci NOT NULL default \'en\',
  								  `openid` longtext collate utf8_unicode_ci,
  								  PRIMARY KEY  (`id`),
  								  UNIQUE KEY `username` (`username`),
  								  KEY `copname` (`copname`)
								  ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create users table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `widgets` (
							`widgetid` varchar(50) collate utf8_unicode_ci NOT NULL,
							`widgetname` varchar(50) collate utf8_unicode_ci NOT NULL,
							`visible` tinyint(1) unsigned NOT NULL default \'0\',
							`copname` varchar(50) collate utf8_unicode_ci NOT NULL,
							`category` smallint(6) unsigned default NULL,
							`description` longtext collate utf8_unicode_ci,
							`authkey` tinyblob,
							PRIMARY KEY  (`widgetid`),
							KEY `copname` (`copname`),
							KEY `category` (`category`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create widgets table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `widget_app` (
							`widget_id` varchar(50) collate utf8_unicode_ci NOT NULL,
							`service_id` int(11) NOT NULL,
							PRIMARY KEY  (`widget_id`,`service_id`)
							) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create widget_app table',
													   mysql_error());
				}
				if (!@mysql_query('CREATE TABLE `widget_tags` (
							`widget` varchar(50) collate utf8_unicode_ci NOT NULL,
							`tag` varchar(50) collate utf8_unicode_ci NOT NULL,
							PRIMARY KEY  (`widget`,`tag`),
							KEY `tag` (`tag`)
							) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_TABLE,
													   'Unable to create widget_tags table',
													   mysql_error());
				}
				if (!@mysql_query('ALTER TABLE `interface`
							ADD CONSTRAINT `interface_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `users` (`id`) ON DELETE CASCADE,
							ADD CONSTRAINT `interface_ibfk_2` FOREIGN KEY (`widgetid`) REFERENCES `widgets` (`widgetid`) ON DELETE CASCADE;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_FOREIGN_KEYS,
													   'Unable to create interface table\'s foreign key(s)',
													   mysql_error());
				}
				if (!@mysql_query('ALTER TABLE `interface_preferences`
							ADD CONSTRAINT `interface_preferences_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `users` (`id`) ON DELETE CASCADE,
							ADD CONSTRAINT `interface_preferences_ibfk_2` FOREIGN KEY (`widgetid`) REFERENCES `widgets` (`widgetid`) ON DELETE CASCADE;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_FOREIGN_KEYS,
													   'Unable to create interface_preferences table\'s foreign key(s)',
													   mysql_error());
				}
				if (!@mysql_query('ALTER TABLE `users`
							ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY (`copname`) REFERENCES `cops` (`copname`) ON DELETE SET NULL;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_FOREIGN_KEYS,
													   'Unable to create users table\'s foreign key(s)',
													   mysql_error());
				}
				if (!@mysql_query('ALTER TABLE `widgets`
							ADD CONSTRAINT `widgets_ibfk_3` FOREIGN KEY (`copname`) REFERENCES `cops` (`copname`) ON DELETE CASCADE,
							ADD CONSTRAINT `widgets_ibfk_4` FOREIGN KEY (`category`) REFERENCES `categories` (`id`) ON DELETE SET NULL;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_FOREIGN_KEYS,
													   'Unable to create widgets table\'s foreign key(s)',
													   mysql_error());
				}
				if (!@mysql_query('ALTER TABLE `widget_tags`
							ADD CONSTRAINT `widget_tags_ibfk_1` FOREIGN KEY (`widget`) REFERENCES `widgets` (`widgetid`) ON DELETE CASCADE,
							ADD CONSTRAINT `widget_tags_ibfk_2` FOREIGN KEY (`tag`) REFERENCES `tags` (`label`) ON DELETE CASCADE;'))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_FOREIGN_KEYS,
													   'Unable to create widget_tags table\'s foreign key(s)',
													   mysql_error());
				}
				// -- End of tables creation.
				
				// Basic data insertion.
				if (!@mysql_query("INSERT INTO `cops` (`copname`, `coplabel`) VALUES ('cop1', NULL);"))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_DATA,
													   'Unable to create the base Community of Practice entry',
													   mysql_error());
				}
				if (!@mysql_query("INSERT INTO `users` (`id`, `username`, `password`, `copname`, `level`, `openid`) VALUES
								(1, 'root', '63a9f0ea7bb98050796b649e85481845', 'cop1', 2, NULL);"))
				{
					rollBackDBMS();
					throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_INSERT_DATA,
													   'Unable to create the root user entry',
													   mysql_error());
				}
				// -- End of basic data insertion.
				
				@mysql_query('COMMIT;');
				// -- End of transaction.
			}
			else
			{
				throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CREATE_DB,
																 'Unable to create database or to connect to it.',
																 mysql_error());
			}


		}
		else
		{
			throw new DatabaseInstallException(DatabaseInstallException::FAILED_TO_CONNECT,
															 'Unable to connect to the RDBMS',
															 mysql_error());
		}
	}
	
	private function rollBackDBMS()
	{
		@mysql_query('ROLLBACK');
	}
	
	private function clearEndOfURI($uri)
	{
		if (substr($uri, strlen($uri) - 1, 1) == '/')
			return substr($uri, 0, strlen($uri) - 1);
		else
			return $uri;
	}
}
?>